package com.guozhi.demo.dev;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.nio.charset.Charset;
import java.util.Objects;
import java.util.stream.Collectors;

public class LoadClass {

    // javac 命令
    private static final String JAVAC_CMD = "javac -d %s %s";

    // 默认类加载器
    private ClassLoader classLoader = getClass().getClassLoader();

    /**
     * 将java文件编译成class文件
     * @param javaFilePath .java文件的路径（相对于resource目录）
     *
     */
    private void compileClass(String javaFilePath) throws IOException, InterruptedException {
        URL javaFileUrl = classLoader.getResource(javaFilePath);
        if(javaFileUrl == null){
            throw new IOException(javaFilePath+" 文件找不到！");
        }
        // 取当前项目的根目录 classes
        String classFilePath = this.getClass().getResource("/").getPath();
        String cmd = String.format(JAVAC_CMD, classFilePath, javaFileUrl.getPath());
        // 调用系统指令，执行javac过程
        Process process = Runtime.getRuntime().exec(cmd);
        // 等待系统命令执行完成
        process.waitFor();
        InputStream execResultIO = process.getErrorStream();
        BufferedReader execResultReader = new BufferedReader(new InputStreamReader(execResultIO, Charset.forName("GBK")));
        String result =  execResultReader.lines().collect(Collectors.joining("\n"));
        // 关闭结果输出流
        execResultReader.close();
        // 关闭子进程
        process.destroy();
        // 输出编译结果
        System.out.println(String.format("编辑 %s.java文件结果:\n%s", javaFilePath, result));
    }

    /**
     * 加载到虚拟机
     *
     * @param javaFilePath .java文件的路径（相对于resource目录）
     */
    @SuppressWarnings("rawtypes")
    public Class load(String javaFilePath) throws IOException, ClassNotFoundException, InterruptedException {
        compileClass(javaFilePath);
        String classPath = getCLassPath(javaFilePath);
        URL classFileUrl = classLoader.getResource(classPath);
        if (classFileUrl == null){
            throw new IOException(String.format("编译 %s.java文件失败！", javaFilePath));
        }
        String totalCLassName = classPath.replace("/", ".").substring(0, classPath.lastIndexOf(".class"));
        // 将 .class文件加载到虚拟机中
        return classLoader.loadClass(totalCLassName);
    }

    /**
     *
     * @param javaFilePath java文件的资源目录位置
     * @return class文件的位置
     */
    private String getCLassPath(String javaFilePath) throws IOException {
        URL javaFileUrl = classLoader.getResource(javaFilePath);
        BufferedReader javaFileBuffer = new BufferedReader(new InputStreamReader(Objects.requireNonNull(javaFileUrl).openStream()));
        String s1 = javaFileBuffer.readLine();
        javaFileBuffer.close();
        if (!s1.contains("package")){
            throw new IOException(String.format("%s 文件的package名称未找到，请确保package定义在java文件第一行的第一条语句", javaFilePath));
        }
        String packageName = s1.substring(s1.indexOf("package") + 7, s1.indexOf(";")).trim();
        String className = javaFilePath.substring(javaFilePath.lastIndexOf('/') + 1, javaFilePath.lastIndexOf(".java"));
        StringBuilder classPath = new StringBuilder(packageName.replace(".", "/"));
        classPath.append('/');
        classPath.append(className);
        classPath.append(".class");
        return classPath.toString();
    }


}
